// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "Engine/World.h"
#include "GameplayTagContainer.h"

#include "LyraCameraMode.generated.h"

#define UE_API LYRAGAME_API

class AActor;
class UCanvas;
class ULyraCameraComponent;

/**
 * ELyraCameraModeBlendFunction
 *
 *	用于在相机模式之间过渡的混合函数。
 */
UENUM(BlueprintType)
enum class ELyraCameraModeBlendFunction : uint8
{
	// 执行简单的线性插值。
	Linear,

	// 立即加速，但平滑减速到目标。缓动量由指数控制。
	EaseIn,

	// 平滑加速，但不会减速到目标。缓动量由指数控制。
	EaseOut,

	// 平滑加速和减速。缓动量由指数控制。
	EaseInOut,

	COUNT	UMETA(Hidden) // 隐藏的计数枚举值
};


/**
 * FLyraCameraModeView
 *
 *	由相机模式产生的视图数据，用于混合相机模式。
 */
struct FLyraCameraModeView
{
public:

	FLyraCameraModeView();

	void Blend(const FLyraCameraModeView& Other, float OtherWeight);

public:

	FVector Location; // 位置
	FRotator Rotation; // 旋转
	FRotator ControlRotation; // 控制旋转
	float FieldOfView; // 视野
};


/**
 * ULyraCameraMode
 *
 *	所有相机模式的基类。
 */
UCLASS(MinimalAPI, Abstract, NotBlueprintable)
class ULyraCameraMode : public UObject
{
	GENERATED_BODY()

public:

	UE_API ULyraCameraMode();

	UE_API ULyraCameraComponent* GetLyraCameraComponent() const;

	UE_API virtual UWorld* GetWorld() const override;

	UE_API AActor* GetTargetActor() const;

	const FLyraCameraModeView& GetCameraModeView() const { return View; } // 获取相机模式视图

	// 当此相机模式在相机模式堆栈上激活时调用。
	virtual void OnActivation() {};

	// 当此相机模式在相机模式堆栈上停用时调用。
	virtual void OnDeactivation() {};

	UE_API void UpdateCameraMode(float DeltaTime);

	float GetBlendTime() const { return BlendTime; } // 获取混合时间
	float GetBlendWeight() const { return BlendWeight; } // 获取混合权重
	UE_API void SetBlendWeight(float Weight);

	FGameplayTag GetCameraTypeTag() const // 获取相机类型标签
	{
		return CameraTypeTag;
	}

	UE_API virtual void DrawDebug(UCanvas* Canvas) const;

protected:

	UE_API virtual FVector GetPivotLocation() const; // 获取枢轴位置
	UE_API virtual FRotator GetPivotRotation() const; // 获取枢轴旋转

	UE_API virtual void UpdateView(float DeltaTime); // 更新视图
	UE_API virtual void UpdateBlending(float DeltaTime); // 更新混合

protected:
	// 一个标签，可以被关心某种相机模式何时激活的游戏玩法代码查询，而无需询问特定模式（例如，当瞄准瞄准镜以获得更高精度时）
	UPROPERTY(EditDefaultsOnly, Category = "Blending")
	FGameplayTag CameraTypeTag;

	// 由相机模式产生的视图输出。
	FLyraCameraModeView View; // 相机模式视图

	// 水平视野（以度为单位）。
	UPROPERTY(EditDefaultsOnly, Category = "View", Meta = (UIMin = "5.0", UIMax = "170", ClampMin = "5.0", ClampMax = "170.0"))
	float FieldOfView;

	// 最小视角俯仰（以度为单位）。
	UPROPERTY(EditDefaultsOnly, Category = "View", Meta = (UIMin = "-89.9", UIMax = "89.9", ClampMin = "-89.9", ClampMax = "89.9"))
	float ViewPitchMin;

	// 最大视角俯仰（以度为单位）。
	UPROPERTY(EditDefaultsOnly, Category = "View", Meta = (UIMin = "-89.9", UIMax = "89.9", ClampMin = "-89.9", ClampMax = "89.9"))
	float ViewPitchMax;

	// 混合此模式所需的时间。
	UPROPERTY(EditDefaultsOnly, Category = "Blending")
	float BlendTime;

	// 用于混合的函数。
	UPROPERTY(EditDefaultsOnly, Category = "Blending")
	ELyraCameraModeBlendFunction BlendFunction;

	// 混合函数使用的指数，用于控制曲线的形状。
	UPROPERTY(EditDefaultsOnly, Category = "Blending")
	float BlendExponent;

	// 用于确定混合权重的线性混合Alpha值。
	float BlendAlpha; // 混合Alpha值

	// 使用混合Alpha和函数计算的混合权重。
	float BlendWeight; // 混合权重

protected:
	/** 如果为true，跳过所有插值并将相机置于理想位置。下一帧自动设置为false。 */
	UPROPERTY(transient)
	uint32 bResetInterpolation:1; // 重置插值标志
};


/**
 * ULyraCameraModeStack
 *
 *	用于混合相机模式的堆栈。
 */
UCLASS()
class ULyraCameraModeStack : public UObject
{
	GENERATED_BODY()

public:

	ULyraCameraModeStack();

	void ActivateStack(); // 激活堆栈
	void DeactivateStack(); // 停用堆栈

	bool IsStackActivate() const { return bIsActive; } // 检查堆栈是否激活

	void PushCameraMode(TSubclassOf<ULyraCameraMode> CameraModeClass); // 推入相机模式

	bool EvaluateStack(float DeltaTime, FLyraCameraModeView& OutCameraModeView); // 评估堆栈

	void DrawDebug(UCanvas* Canvas) const; // 绘制调试信息

	// 获取与顶层关联的标签及其混合权重
	void GetBlendInfo(float& OutWeightOfTopLayer, FGameplayTag& OutTagOfTopLayer) const;

protected:

	ULyraCameraMode* GetCameraModeInstance(TSubclassOf<ULyraCameraMode> CameraModeClass); // 获取相机模式实例

	void UpdateStack(float DeltaTime); // 更新堆栈
	void BlendStack(FLyraCameraModeView& OutCameraModeView) const; // 混合堆栈

protected:

	bool bIsActive; // 堆栈是否激活

	UPROPERTY()
	TArray<TObjectPtr<ULyraCameraMode>> CameraModeInstances; // 相机模式实例数组

	UPROPERTY()
	TArray<TObjectPtr<ULyraCameraMode>> CameraModeStack; // 相机模式堆栈数组
};

#undef UE_API